package com.link.base.base.fund.service;

import com.link.base.base.fund.dao.mybatis.mapper.BillAccountMapper;
import com.link.base.base.fund.model.BillAccount;
import com.link.base.base.fund.model.BillAccountDetail;
import com.link.base.base.fund.model.BillDetailModel;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.service.ServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.KeyGenerateService;
import com.link.core.util.DateUtil;
import com.link.core.util.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Copyright  hande Company. All Rights Reserved.
 *
 * @author unknwon
 * @version 1.0
 * @date: 2018/11/12 10:10
 */

@Service
public class BillAccountServiceImpl extends BasicServiceImpl<BillAccount> implements BillAccountService {

    /**对账单状态**/
    /**
     * 对账单 已生成
     **/
    private static final String BILL_ACCOUNT_GENERATED = "Generated";
    /**
     * 对账单 发布
     **/
    private static final String BILL_ACCOUNT_UNCONFIRMED = "Unconfirmed";
    /**
     * 对账单 确认
     **/
    private static final String BILL_ACCOUNT_CONFIRMED = "Confirmed";
    /**
     * 对账单 驳回
     **/
    private static final String BILL_ACCOUNT_REJECTED = "Rejected";

    /**
     * 交易类型
     */
    private static final String DEALER_TRAN_DETAIL_SOURCE_TYPE_OCCUPY = "OrderPaymentOccupy";
    private static final String DEALER_TRAN_DETAIL_SOURCE_TYPE_RELEASE = "OrderPaymentRelease";

    /**资金账户类型**/
    /**
     * 返利账户
     */
    private static final String DEALER_ACCOUNT_TYPE_RETURN = "Return Account";
    /**
     * 现金账户
     */
    private static final String DEALER_ACCOUNT_TYPE_CASH = "Cash Account";
    /**
     * 保证金账户
     */
    private static final String DEALER_ACCOUNT_TYPE_DEPOSIT = "Deposit Account";

    @Resource
    private BillAccountMapper billAccountMapper;

    /**
     * 资金账户交易明细
     */
    @Resource
    private DealerTransactionDetailService dealerTransactionDetailService;

    /**
     * 对账单生成明细
     */
    @Resource
    private BillAccountDetailService billAccountDetailService;

    @Resource
    private KeyGenerateService keyGenerateService;

    @Override
    public BasicMapper<BillAccount> getBasicMapper() {
        return billAccountMapper;
    }

    @Override
    public void confirmBillAccount(BillAccount entity) throws Exception {
        Long id = entity.getId();
        BillAccount billAccount = this.queryById(id);
        String unconfirmed = "Unconfirmed";
        if (!StringUtils.equals(unconfirmed, billAccount.getStatus()) && StringUtils.isNotBlank(billAccount.getStatus())) {
            throw new ServiceException("FUND-002");
        }
        //状态设为已确认
        billAccount.setStatus("Confirmed");
        billAccount.setConfirmDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
        billAccount.setConfirmBy(entity.getConfirmBy());
        this.update(billAccount);
    }

    @Override
    public void rejectBillAccount(BillAccount entity) throws Exception {
        Long id = entity.getId();
        BillAccount billAccount = this.queryById(id);
        String unconfirmed = "Unconfirmed";
        if (!StringUtils.equals(unconfirmed, billAccount.getStatus()) && StringUtils.isNotBlank(billAccount.getStatus())) {
            throw new ServiceException("FUND-002");
        }
        //状态设为已驳回
        billAccount.setStatus("Rejected");
        this.update(billAccount);
    }

    /**
     * 更新对账单状态
     *
     * @param billAccount 对账单对象
     * @param status      对账单状态
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void updateStatus(BillAccount billAccount, String status) throws Exception {
        if (StringUtils.equals(status, BILL_ACCOUNT_GENERATED)) {
            //可多次生成
            generateAccountBillDeatil(billAccount);
        } else if (StringUtils.equals(status, BILL_ACCOUNT_UNCONFIRMED)) {
            if (StringUtils.equals(billAccount.getStatus(), BILL_ACCOUNT_UNCONFIRMED)) {
                throw new ServiceException("FUND-003");
            }
            billAccount.setPublicDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
        } else if (StringUtils.equals(status, BILL_ACCOUNT_CONFIRMED)) {
            if (StringUtils.equals(billAccount.getStatus(), BILL_ACCOUNT_CONFIRMED)) {
                throw new ServiceException("FUND-004");
            }
            billAccount.setConfirmDate(DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
        } else if (StringUtils.equals(status, BILL_ACCOUNT_REJECTED)) {
            if (StringUtils.equals(billAccount.getStatus(), BILL_ACCOUNT_REJECTED)) {
                throw new ServiceException("FUND-005");
            }
        } else {
            throw new ServiceException("FUND-006");
        }
        billAccount.setStatus(status);
        super.update(billAccount);
    }

    /**
     * 对对账单生成资金交易明细
     *
     * @param billAccount 对账单对象
     */
    private void generateAccountBillDeatil(BillAccount billAccount) throws Exception {

        // 对账单对应的客户id
        Long accntId = billAccount.getAccntId();
        if (null == accntId) {
            throw new ServiceException("FUND-007");
        }
        if (StringUtils.isBlank(billAccount.getStartDate())) {
            throw new ServiceException("FUND-008");
        }
        if (StringUtils.isBlank(billAccount.getEndDate())) {
            throw new ServiceException("FUND-009");
        }
        /**
         *  通过客户和区间时间查到该客户的期间资金交易明细
         */
        BillDetailModel billDetailModel = new BillDetailModel();
        billDetailModel.setAccntId(accntId);
        List<String> params = new ArrayList<String>();
        params.add(DEALER_TRAN_DETAIL_SOURCE_TYPE_OCCUPY);
        params.add(DEALER_TRAN_DETAIL_SOURCE_TYPE_RELEASE);
        billDetailModel.setList(params);
        //期间开始时间
        billDetailModel.setPeriodStartDate(billAccount.getStartDate());
        //期间结束时间
        billDetailModel.setPeriodEndDate(billAccount.getEndDate());
        List<BillDetailModel> transactionDetailList = dealerTransactionDetailService.queryAllByPerAndAccnt(billDetailModel);

        BillAccountDetail billAccountDetail = null;
        List<BillAccountDetail> insertList = null;
        if (!CollectionUtils.isEmpty(transactionDetailList)) {
            billAccountDetail = new BillAccountDetail();
            billAccountDetail.setHeadId(billAccount.getId());
            billAccountDetailService.deleteByHeadId(billAccountDetail);
            insertList = new ArrayList<>();
            for (BillDetailModel bdm : transactionDetailList) {
                BillAccountDetail newbillAccDetai = new BillAccountDetail();
                newbillAccDetai.setId(keyGenerateService.keyGenerate());
                //头id
                newbillAccDetai.setHeadId(billAccount.getId());
                // 资金账户id
                newbillAccDetai.setAccntId(bdm.getHeadId());
                // 交易金额
                newbillAccDetai.setAmount(bdm.getAmount());
                //业务单号
                newbillAccDetai.setSourceNum(bdm.getSourceNum());
                //交易类型
                newbillAccDetai.setSourceType(bdm.getSourceType());
                //交易时间
                newbillAccDetai.setDealTime(bdm.getDealTime());
                //摘要
                newbillAccDetai.setTextDigest(bdm.getTextDigest());
                insertList.add(newbillAccDetai);
            }
            billAccountDetailService.batchInsert(insertList);
        }
    }

    /**
     * 对账单余额汇总
     *
     * @param billAccount 对账单实例
     * @return billAccount
     * @throws Exception
     */
    @Override
    public BillAccount sumDealerBalance(BillAccount billAccount) throws Exception {

        if (Objects.isNull(billAccount)) {
            throw new ServiceException("FUND-010");
        }
        // 对账单对应的客户id
        Long accntId = billAccount.getAccntId();
        String startDate = billAccount.getStartDate();
        String endDate = billAccount.getEndDate();
        if (null == accntId) {
            throw new ServiceException("FUND-007");
        }
        if (StringUtils.isBlank(startDate)) {
            throw new ServiceException("FUND-008");
        }
        if (StringUtils.isBlank(endDate)) {
            throw new ServiceException("FUND-009");
        }
        //期初余额类型
        String actionTypeRemain = "remainAmount";
        //期末余额类型
        String actionTypeTotal = "totalAmount";
        /**
         *  通过客户和区间时间查到该客户的期间资金交易明细
         */
        List<String> params = new ArrayList<String>();
        params.add(DEALER_TRAN_DETAIL_SOURCE_TYPE_OCCUPY);
        params.add(DEALER_TRAN_DETAIL_SOURCE_TYPE_RELEASE);

        BillAccount returnBillAccount = new BillAccount();

        /**返利期初余额**/
        BillDetailModel result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeRemain, accntId, DEALER_ACCOUNT_TYPE_RETURN, startDate, endDate, params);
        returnBillAccount.setReturnRemainAmount(result.getRemainAmount() == null ? 0.00 : result.getRemainAmount());

        /**返利期末余额**/
        result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeTotal, accntId, DEALER_ACCOUNT_TYPE_RETURN, startDate, endDate, params);
        returnBillAccount.setReturnTotalAmount(result.getTotalAmount() == null ? 0.00 : result.getTotalAmount());

        /**现金期初余额**/
        result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeRemain, accntId, DEALER_ACCOUNT_TYPE_CASH, startDate, endDate, params);
        returnBillAccount.setCashRemainAmount(result.getRemainAmount() == null ? 0.00 : result.getRemainAmount());
        /**现金期末余额**/
        result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeTotal, accntId, DEALER_ACCOUNT_TYPE_CASH, startDate, endDate, params);
        returnBillAccount.setCashTotalAmount(result.getTotalAmount() == null ? 0.00 : result.getTotalAmount());
        /**保证金期初余额**/
        result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeRemain, accntId, DEALER_ACCOUNT_TYPE_DEPOSIT, startDate, endDate, params);
        returnBillAccount.setDepositRemainAmount(result.getRemainAmount() == null ? 0.00 : result.getRemainAmount());
        /**保证金末余额**/
        result = dealerTransactionDetailService.queryBalanceByPerAndAccnt(
                actionTypeTotal, accntId, DEALER_ACCOUNT_TYPE_DEPOSIT, startDate, endDate, params);
        returnBillAccount.setDepositTotalAmount(result.getTotalAmount() == null ? 0.00 : result.getTotalAmount());
        return returnBillAccount;
    }
}
